package mallindex

import (
	"context"
	"fmt"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/jwt"
	"mall/common/utils/pointy"
	"mall/service/blog/rpc/blogclient"
	"mall/service/forum/api/internal/logic/util"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/forum/api/internal/utils/parse"
	"mall/service/product/rpc/productclient"

	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetGoodsListLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetGoodsListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetGoodsListLogic {
	return &GetGoodsListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetGoodsListLogic) GetGoodsList(
	req *types.GetGoodsListReq,
	headers *[]*types.Header,
) (resp *types.GoodsListResp, err error) {
	userId := jwt.GetUserId(l.ctx)

	page, pageSize := parse.ParsePageInfo(
		req.Current,
		req.PageSize,
		l.svcCtx.Config.Query.DefaultAmount,
		l.svcCtx.Config.Query.MaxAmount,
	)

	platformId := globalkey.ThirdPartyPlatformWechatMini

	preload := "product:Id,Title,Slug,Excerpt"
	eagerLoad := "product:productMeta,productMedia,productRelationship"
	preload += ";productMedia:Uid,Url,Thumbnail,Order"
	preload += ";productRelationship:PerfumeId,PerfumeName,PerfumeSlug,BrandId,BrandName,BrandSlug"
	preload += ";productMeta:mediaUrl,retailPriceMin,couterPriceMin,hotSell" // 此行必须在最后，后面可能补字段

	var preFilterEntity string
	var preFilter string
	if req.Pid != nil && *req.Pid > 0 { // 指定香水ID
		preFilterEntity = "productRelationship"
		preFilter = "PerfumeId,equalTo:" + strconv.FormatUint(*req.Pid, 10)
	} else if req.Bid != nil && *req.Bid > 0 { // 指定品牌ID
		preFilterEntity = "productRelationship"
		preFilter = "BrandId,equalTo:" + strconv.FormatUint(*req.Bid, 10)
	} else if req.RecommendStatus != nil {
		preFilterEntity = "productMeta"
		preFilter = "recommend,equalTo:" + strconv.FormatInt(int64(*req.RecommendStatus), 10)
	} else if req.Eid != nil && req.Sid != nil {
		pids, err := l.getKBPostList(*req.Eid, *req.Sid, page, pageSize)
		if err != nil {
			return nil, err
		}

		preFilterEntity = "productRelationship"
		preFilter = "PerfumeId,in:" + pids
	}

	var filters []string
	if req.Filter != nil && len(strings.TrimSpace(*req.Filter)) > 0 {
		filterMap := util.GetFilterMap(strings.TrimSpace(*req.Filter))
		for key, val := range filterMap {
			switch key {
			case "virtual": //虚拟商品
				filters = append(filters, "virtual,equalTo:"+val)
			}
		}
	}
	if req.Type != nil && *req.Type != globalkey.ProductTypePhysical {
		filters = append(filters, "virtual,equalTo:"+strconv.FormatInt(int64(*req.Type), 10))
	} else {
		filters = append(filters, "virtual,equalTo:"+strconv.FormatInt(int64(globalkey.ProductTypePhysical), 10))
	}
	if req.Cid != nil && int64(*req.Cid) == l.svcCtx.Config.Query.TesterCategoryId {
		filters = append(filters, "CategoryId,equalTo:"+strconv.FormatInt(l.svcCtx.Config.Query.TesterCategoryId, 10))
		preload += ",gemPriceMin,gemPriceMax;productVariation:Id"
		eagerLoad += ",productVariation"
	} else {
		filters = append(filters, "CategoryId,notEqualTo:"+strconv.FormatInt(l.svcCtx.Config.Query.TesterCategoryId, 10))
	}
	filters = append(filters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.StatusEnabled), 10))

	var keyword string
	if req.Title != nil && len(strings.TrimSpace(*req.Title)) > 0 {
		filters = append(filters, "Title,contain:"+strings.TrimSpace(*req.Title))
		keyword = strings.TrimSpace(*req.Title)
	}
	if req.Slug != nil && len(strings.TrimSpace(*req.Slug)) > 0 {
		filters = append(filters, "Slug,contain:"+strings.TrimSpace(*req.Slug))
		if len(keyword) == 0 {
			keyword = strings.TrimSpace(*req.Slug)
		}
	}

	var sorter *string
	if req.Sorter != nil {
		sorter = pointy.GetPointer(strings.TrimSpace(*req.Sorter))
	}

	res, err := l.svcCtx.ProductRpc.GetProductList(l.ctx, &productclient.BaseListReq{
		Offset:          uint32((page - 1) * pageSize),
		Limit:           uint32(pageSize),
		Preload:         pointy.GetPointer(preload),
		EagerLoad:       pointy.GetPointer(eagerLoad),
		Filter:          pointy.GetPointer(strings.Join(filters, ";")),
		Sorter:          sorter,
		Search:          req.Search,
		PreFilterEntity: pointy.GetPointer(preFilterEntity),
		PreFilter:       pointy.GetPointer(preFilter),
		VisitorId:       pointy.GetPointer(userId),
		PlatformId:      pointy.GetPointer(platformId),
	})
	if err != nil {
		return nil, err
	}

	var hasNextPage bool
	var hasPreviousPage bool
	if res.HasNextPage != nil && *res.HasNextPage > 0 {
		hasNextPage = true
	}
	if res.HasPreviousPage != nil && *res.HasPreviousPage > 0 {
		hasPreviousPage = true
	}

	resp = &types.GoodsListResp{
		BaseListInfo: types.BaseListInfo{
			HasNextPage:     hasNextPage,
			HasPreviousPage: hasPreviousPage,
		},
	}

	if len(res.List) > 0 {
		for _, v := range res.List {
			// logrus.Info(fmt.Sprintf("GetProductList item: %+v", v))
			var retailPriceMin *string
			var couterPriceMin *string
			var isNew *bool
			var isHot *bool
			// var mediaId *uint64
			var mediaUrl *string
			var gemPriceMin string
			var gemPriceMax string
			if len(v.Meta) > 0 {
				for _, m := range v.Meta {
					if m.Key == nil || m.Value == nil {
						continue
					}

					val := *m.Value
					switch *m.Key {
					case "retailPriceMin":
						retailPriceMin = pointy.GetPointer(val)
					case "couterPriceMin":
						couterPriceMin = pointy.GetPointer(val)
					case "gemPriceMin":
						gemPriceMin = val
					case "gemPriceMax":
						gemPriceMax = val
					case "isNew":
						if val == "1" {
							isNew = pointy.GetPointer(true)
						}
					case "isHot":
						if val == "1" {
							isHot = pointy.GetPointer(true)
						}
					case "hotSell":
						if val == "1" {
							isHot = pointy.GetPointer(true)
						}
					// case "mediaId":
					// 	if i, err := strconv.ParseInt(val, 10, 64); err == nil {
					// 		mediaId = pointy.GetPointer(uint64(i))
					// 	}
					case "mediaUrl":
						mediaUrl = pointy.GetPointer(val)
					}
				}
			}

			if gemPriceMin != gemPriceMax { // Todo: 暂时限制，不允许试香有多个规格（也就不会有多个兑换积分）
				continue
			}

			// var brand *types.KbEntryInfo
			var brandTitle *string
			// var perfume *types.KbEntryInfo
			if len(v.Relations) > 0 {
				for _, m := range v.Relations {
					if m.Key != nil {
						switch *m.Key {
						case globalkey.ProductRelationNameBrand:
							// brand = &types.KbEntryInfo{
							// 	Id:    m.Id,
							// 	Title: m.Name,
							// 	Slug:  m.Slug,
							// }
							brandTitle = m.Name
							// case globalkey.ProductRelationNamePerfume:
							// 	perfume = &types.KbEntryInfo{
							// 		Id:    m.Id,
							// 		Title: m.Name,
							// 		Slug:  m.Slug,
							// 	}
						}
					}
				}
			}

			// var photos []*types.MediaInfo
			if len(v.Media) > 0 {
				for _, m := range v.Media {
					if mediaUrl != nil {
						break
					}

					var url string
					if m.Url != nil && len(*m.Url) > 0 {
						url = *m.Url
					}
					if len(url) == 0 && m.Uri != nil && len(*m.Uri) > 0 {
						url = *m.Uri
					}
					// photos = append(photos, &types.MediaInfo{
					// 	Uid: m.Uid,
					// 	Url: pointy.GetPointer(url),
					// })
					mediaUrl = pointy.GetPointer(url)
				}
			}

			var preTag *string
			if isHot != nil && *isHot {
				preTag = pointy.GetPointer("热卖")
			} else if isNew != nil && *isNew {
				preTag = pointy.GetPointer("新品")
			}

			var skus []*types.ProductVariationInfo
			if len(v.Skus) > 0 {
				for _, sku := range v.Skus {
					skus = append(skus, &types.ProductVariationInfo{
						Id: sku.Id,
					})
				}
			}

			resp.List = append(resp.List, &types.GoodsInfo{
				Id:     v.Id,
				PreTag: preTag,
				// Tags:          []string{"兔毛", "手感好"},
				Brand:           brandTitle,
				Title:           v.Title,
				Slug:            v.Slug,
				Excerpt:         v.Excerpt,
				MinPrice:        retailPriceMin,
				CounterPriceMin: couterPriceMin,
				GemPriceMin:     pointy.GetPointer(gemPriceMin),
				// OriginalPrice: pointy.GetPointer("189.00"),
				ImageUrl: mediaUrl,
				// Stores:        pointy.GetPointer(uint32(20)),
				Skus: skus,
			})
		}

		if req.Current != nil && *req.Current == 1 && len(keyword) > 0 {
			logRes, err := l.svcCtx.ProductRpc.SearchLog(l.ctx, &productclient.SearchLogReq{
				Keyword:    pointy.GetPointer(keyword),
				VisitorId:  pointy.GetPointer(userId),
				PlatformId: pointy.GetPointer(platformId),
			})
			if err != nil {
				logrus.Info(fmt.Sprintf("GetProductList SearchLog err: %+v", err))
			} else {
				resp.SearchId = pointy.GetPointer(logRes.Id)
			}
		}
	}

	*headers = []*types.Header{
		{
			Key:   "x-class",
			Value: "com.djx.appview.MallIndexPage",
		},
	}

	return resp, nil
}

func (l *GetGoodsListLogic) getKBPostList(
	eid uint64,
	sid uint64,
	page uint64,
	pageSize uint64,
) (pids string, err error) {
	preload := "blogBook:Id"
	var preFilters []string
	preFilters = append(preFilters, "EntryId,equalTo:"+strconv.FormatInt(int64(eid), 10))
	preFilters = append(preFilters, "EntrySectionId,equalTo:"+strconv.FormatInt(int64(sid), 10))
	preFilterEntity := "blogBookRelation"
	var filters []string
	filters = append(filters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.PostStatusPublish), 10))

	res, err := l.svcCtx.BlogRpc.GetKBPostListTmp(l.ctx, &blogclient.BaseListReq{
		Offset:          uint32((page - 1) * pageSize),
		Limit:           uint32(pageSize),
		Preload:         pointy.GetPointer(preload),
		Filter:          pointy.GetPointer(strings.Join(filters, ";")),
		PreFilterEntity: pointy.GetPointer(preFilterEntity),
		PreFilter:       pointy.GetPointer(strings.Join(preFilters, ";")),
	})
	if err != nil {
		return "", err
	}

	if len(res.List) > 0 {
		for _, v := range res.List {
			if v.Id == nil || *v.Id == 0 {
				continue
			}

			pids += strconv.FormatInt(int64(*v.Id), 10)
		}

		return pids, nil
	}

	return "", err
}
